package cn.uil.demo;

import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;

@Component
public class AsyncPostConstructProcessor implements BeanPostProcessor, ApplicationContextAware {

    private ConfigurableListableBeanFactory beanFactory;
    private Executor asyncExecutor;
    private final ConcurrentHashMap<String, CompletableFuture<Void>> initFutures = new ConcurrentHashMap<>();

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.beanFactory = ((ConfigurableApplicationContext) applicationContext).getBeanFactory();
        this.asyncExecutor = applicationContext.getBean("asyncInitExecutor", Executor.class);
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        // 识别所有带有 @AsyncPostConstruct 的方法
        for (Method method : bean.getClass().getDeclaredMethods()) {
            if (method.isAnnotationPresent(AsyncPostConstruct.class)) {
                CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                    try {
                        method.setAccessible(true);
                        method.invoke(bean);
                    } catch (Exception e) {
                        throw new AsyncInitException("Async @PostConstruct failed for " + beanName, e);
                    }
                }, asyncExecutor);

                initFutures.put(beanName, future);
            }
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        // 确保初始化完成前阻塞依赖访问
        CompletableFuture<Void> future = initFutures.get(beanName);
        if (future != null && !future.isDone()) {
            beanFactory.registerDependentBean(beanName, "asyncInitBarrier");
        }
        return bean;
    }

    // 等待所有异步初始化完成
    public void awaitAsyncInitialization() {
        CompletableFuture.allOf(initFutures.values().toArray(new CompletableFuture[0]))
                .orTimeout(5, TimeUnit.MINUTES)
                .join();
    }
}
